#pragma once
#ifndef __LIT__SCRIPT__ENGINE__OGRE__WRAPPERS__HH__
#define __LIT__SCRIPT__ENGINE__OGRE__WRAPPERS__HH__

#include <Ogre.h>
#include <string>
#include <LitPointer.hpp>

namespace Lit
{
	namespace ScriptWrappers
	{
		struct LogWrp
		{
			Ogre::Log * mLog;
		
			LogWrp( ) : mLog( NULL ){}
			LogWrp( Ogre::Log * log ) : mLog( log ){}
			LogWrp( const std::string &name ) : mLog( Ogre::LogManager::getSingleton().createLog(name) ){}
			LogWrp( const LogWrp & rk ) : mLog( rk.mLog ){}

			std::string getName() const { return mLog?mLog->getName():""; }
			bool isDebugOutputEnabled() const { return mLog?mLog->isDebugOutputEnabled():false; }
			bool isFileOutputSuppressed() const { return mLog?mLog->isFileOutputSuppressed():false; }
			bool isTimeStampEnabled() const { return mLog?mLog->isTimeStampEnabled():false; }

			void logMessage( const std::string& message, Ogre::LogMessageLevel lml = Ogre::LML_NORMAL, bool maskDebug = false )
			{ if( mLog ) mLog->logMessage( message, lml, maskDebug ); }

			void setDebugOutputEnabled(bool debugOutput){ if( mLog ) mLog->setDebugOutputEnabled(debugOutput); }
			void setLogDetail(Ogre::LoggingLevel ll){ if( mLog ) mLog->setLogDetail( ll ); }
			void setTimeStampEnabled(bool timeStamp){ if( mLog ) mLog->setTimeStampEnabled( timeStamp ); }

			Ogre::LoggingLevel getLogDetail() const { return mLog?mLog->getLogDetail():Ogre::LL_NORMAL; }
		
			Ogre::Log* getLog(){ return mLog; }
			const Ogre::Log* getLog() const{ return mLog; }
			
			static void Constructor0(LogWrp *self){ new(self) LogWrp(); }
			static void CreateConstructor(const std::string &name, LogWrp *self){ new(self) LogWrp(name); }
			static void CopyConstructor(const LogWrp &other, LogWrp *self){ new(self) LogWrp(other); }
		};
		struct LogMgrWrp
		{
		protected:
			RefPtr<Ogre::LogManager> ptr;
		public:
			LogMgrWrp( RefPtr<Ogre::LogManager> mgr )	: ptr(mgr){}
			LogMgrWrp( )	: ptr(Ogre::LogManager::getSingletonPtr()){}
			
			static void constructor0( LogMgrWrp * self ){ new(self) LogMgrWrp(); }
			static void copy_constructor( const LogMgrWrp& cpy, LogMgrWrp * self ){ new(self) LogMgrWrp(cpy); }

			LogWrp createLog( const std::string &name ){ return LogWrp(ptr->createLog( name ));}
			LogWrp getLog( const std::string &name ){ return LogWrp(ptr->getLog( name ));}
			LogWrp getDefaultLog(){ return LogWrp(ptr->getDefaultLog( ));}
			void logMessage( const std::string &name ){ Ogre::LogManager::getSingleton().logMessage(name); }
			void destroyLog( const std::string &name ){if( ptr ) ptr->destroyLog( name );}
			void destroyLog( LogWrp & log ){if( ptr ) ptr->destroyLog( log.getLog() ); }

			static LogMgrWrp getSingleton(){ return LogMgrWrp(Ogre::LogManager::getSingletonPtr()); }
		};
		struct QuaternionWrapper
		{
			static void Constructor4(Ogre::Real w, Ogre::Real x, Ogre::Real y, Ogre::Real z, Ogre::Quaternion *self);
			static void ConstructorMat3( const Ogre::Matrix3 &mat , Ogre::Quaternion *self);
			static void ConstructorAngle( const Ogre::Radian &angle, const Ogre::Vector3 &axis, Ogre::Quaternion *self);
			static void ConstructorAxes( const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector3 &v2, Ogre::Quaternion *self);
			static void CopyConstructor(const Ogre::Quaternion &other, Ogre::Quaternion *self);
		};
		struct RadianWrapper
		{
			static void Constructor0(Ogre::Radian *self);
			static void DegreeConstructor(const Ogre::Degree& deg, Ogre::Radian *self);
			static void RealConstructor(Ogre::Real r, Ogre::Radian *self);
			static void CopyConstructor(const Ogre::Radian &other, Ogre::Radian *self);
			static std::string ToString( const Ogre::Radian * self );
			static int Compare(const Ogre::Radian &against, const Ogre::Radian *self);
		};
		struct DegreeWrapper
		{
			static void Constructor0(Ogre::Degree *self);
			static void RadianConstructor(const Ogre::Radian& rad, Ogre::Degree *self);
			static void RealConstructor(Ogre::Real r, Ogre::Degree *self);
			static void CopyConstructor(const Ogre::Degree &other, Ogre::Degree *self);
			static int Compare(const Ogre::Degree &against, const Ogre::Degree *self);
		};
		struct Vector3Wrapper
		{
			static void Constructor0(Ogre::Vector3 *self);
			static void Constructor1(Ogre::Real scalar, Ogre::Vector3 *self);
			static void Constructor3( Ogre::Real x, Ogre::Real y, Ogre::Real z, Ogre::Vector3 *self);
			static void CopyConstructor(const Ogre::Vector3 &other, Ogre::Vector3 *self);
			static int Compare(const Ogre::Vector3 &against, const Ogre::Vector3 *self);
		};
		struct Vector2Wrapper
		{
			static void Constructor0(Ogre::Vector2 *self);
			static void Constructor1( Ogre::Real scalar, Ogre::Vector2 *self );
			static void Constructor2( Ogre::Real x, Ogre::Real y, Ogre::Vector2 *self);

			static void CopyConstructor(const Ogre::Vector2 &other, Ogre::Vector2 *self);
			static int Compare(const Ogre::Vector2 &against, const Ogre::Vector2 *self);
		};
		struct Vector4Wrapper
		{
			static void Constructor0( Ogre::Vector4 *self );
			static void Constructor1( const Ogre::Real scalar, Ogre::Vector4 *self );
			static void Constructor4( const Ogre::Real x, const Ogre::Real y, const Ogre::Real z, const Ogre::Real w, Ogre::Vector4 *self );
			static void ConstructorV3( const Ogre::Vector3 &vec, Ogre::Vector4 *self );

			static void CopyConstructor(const Ogre::Vector4 &other, Ogre::Vector4 *self);	
		};
		struct Matrix3Wrapper
		{
			static void Constructor0( Ogre::Matrix3 *self );
			static void Constructor9( Ogre::Real fEntry00, Ogre::Real fEntry01, Ogre::Real fEntry02,
									Ogre::Real fEntry10, Ogre::Real fEntry11, Ogre::Real fEntry12,
									Ogre::Real fEntry20, Ogre::Real fEntry21, Ogre::Real fEntry22, Ogre::Matrix3 *self );
			static void CopyConstructor(const Ogre::Matrix3 &other, Ogre::Matrix3 *self);
		};
		
		struct AABBWrapper
		{
			static void Constructor0( Ogre::AxisAlignedBox*self )
			{ new(self) Ogre::AxisAlignedBox(); }
			static void Constructor2( const Ogre::Vector3& min, const Ogre::Vector3 &max, Ogre::AxisAlignedBox*self )
			{ new(self) Ogre::AxisAlignedBox(min, max); }
			static void Constructor6( Ogre::Real mX, Ogre::Real mY, Ogre::Real mZ, Ogre::Real MX, Ogre::Real MY, Ogre::Real MZ, Ogre::AxisAlignedBox*self )
			{ new(self) Ogre::AxisAlignedBox(mX, mY,mZ, MX,MY,MZ); }
			static void ConstructorCopy( const Ogre::AxisAlignedBox& b, Ogre::AxisAlignedBox*self )
			{ new(self) Ogre::AxisAlignedBox(b); }
			static Ogre::AxisAlignedBox getBOX_NULL()
			{ return Ogre::AxisAlignedBox::BOX_NULL; }
			static void setBOX_NULL(const Ogre::AxisAlignedBox& )
			{ }
		};
		struct ColourWrp
		{
			static void Construct0( Ogre::ColourValue*self )
			{ new(self) Ogre::ColourValue(); }

			static void Construct4( Ogre::ColourValue*self, Ogre::Real r = 1.0f, Ogre::Real g = 1.0f, Ogre::Real b = 1.0f, Ogre::Real a = 1.0f )
			{ new(self) Ogre::ColourValue( r, g, b, a ); }

			static void ConstructCopy( const Ogre::ColourValue& b, Ogre::ColourValue*self )
			{ new(self) Ogre::ColourValue(b); }

			
			static Ogre::ColourValue ZERO(){ return Ogre::ColourValue::ZERO; }
			static Ogre::ColourValue Black(){ return Ogre::ColourValue::Black; }
			static Ogre::ColourValue White(){ return Ogre::ColourValue::White; }
			static Ogre::ColourValue Red(){ return Ogre::ColourValue::Red; }
			static Ogre::ColourValue Green(){ return Ogre::ColourValue::Green; }
			static Ogre::ColourValue Blue(){ return Ogre::ColourValue::Blue; }
		};
		struct EntityWrp;
		struct SceneMgrWrp;
		struct SceneNodeWrp
		{
			friend struct SceneMgrWrp;
			friend struct EntityWrp;
		protected:
			Ogre::SceneNode * mNode;
		public:
			SceneNodeWrp( Ogre::SceneNode * n );
			SceneNodeWrp( );
			SceneNodeWrp( const SceneNodeWrp& rk );
			~SceneNodeWrp();
			
			static void con_0( SceneNodeWrp*self );
			static void con_copy( const SceneNodeWrp& oth, SceneNodeWrp*self );

			void attachObject( EntityWrp& obj );
			void detachObject( EntityWrp& obj );
			void detachAllObjects( );

			SceneNodeWrp createChildSceneNode();
			
			void setPosition( const Ogre::Vector3& pos );
			void setPosition( Ogre::Real x, Ogre::Real y, Ogre::Real z );
			void setOrientation( const Ogre::Quaternion& pos );
			void setOrientation( Ogre::Real w, Ogre::Real x, Ogre::Real y, Ogre::Real z );
			void setScale( const Ogre::Vector3& pos );
			void setScale( Ogre::Real x, Ogre::Real y, Ogre::Real z );
			
			Ogre::Vector3 getPosition() const;
			Ogre::Quaternion getOrientation() const;
			Ogre::Vector3 getScale() const;

			void setVisible( bool vis, bool cascade=true );
		};
		struct EntityWrp
		{
			friend struct SceneMgrWrp;
			friend struct SceneNodeWrp;
		protected:
			Ogre::Entity * mNode;
		public:
			EntityWrp( Ogre::Entity * n );
			EntityWrp( );
			EntityWrp( const EntityWrp& rk );
			~EntityWrp();
			
			static void con_0( EntityWrp*self );
			static void con_copy( const EntityWrp& oth, EntityWrp*self );

			SceneNodeWrp getParentSceneNode() const;

			void detachFromParent();

			std::string getName() const;
			std::string getMeshName() const;
			std::string getMaterialName( unsigned int id = 0 ) const;
		};
		struct SceneMgrWrp
		{
		protected:
		public:
			Ogre::SceneManager * mScene;
			SceneMgrWrp( Ogre::SceneManager * n );
			SceneMgrWrp( );
			SceneMgrWrp( const SceneMgrWrp& rk );
			~SceneMgrWrp();
			
			static void con_0( SceneMgrWrp*self );
			static void con_copy( const SceneMgrWrp& oth, SceneMgrWrp*self );
			
			void setAmbientLight( Ogre::Real r, Ogre::Real g, Ogre::Real b){ if( mScene ) mScene->setAmbientLight( Ogre::ColourValue( r, g, b ) ); }
			void setSkyBox( bool enabled, const std::string &sky, Ogre::Real distance = 5000.0f ){ if( mScene ) mScene->setSkyBox( enabled, sky, distance ); }
			void setSkyDome( bool enabled, const std::string &sky, Ogre::Real curv = 10.0f, Ogre::Real tiling=8.0f, Ogre::Real distance=4000.0f ){ if( mScene ) mScene->setSkyDome( enabled, sky, curv, tiling, distance ); }

			std::string getName() const{ return mScene?mScene->getName():""; }
			
			SceneNodeWrp getSceneNode( const std::string &name );
			void destroySceneNode( SceneNodeWrp & node );

			EntityWrp createEntity( const std::string &mesh, const std::string &name = "" );
			EntityWrp getEntity( const std::string &name );

			void destroyEntity( const std::string &name );
			void destroyEntity( EntityWrp &name );

			SceneNodeWrp getRootSceneNode();
			void clearScene();
		};
	};
};

#endif